﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms.Design;
using System.Windows.Forms.Layout;

namespace System.Windows.Forms;

/// <summary>
///  A ToolStripButton that can display a popup.
/// </summary>
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)]
public partial class ToolStripDropDownButton : ToolStripDropDownItem
{
    private bool _showDropDownArrow = true;
    private byte _openMouseId;

    /// <summary>
    ///  Constructs a ToolStripButton that can display a popup.
    /// </summary>
    public ToolStripDropDownButton()
    {
        Initialize();
    }

    public ToolStripDropDownButton(string? text)
        : base(text, image: null, onClick: null)
    {
        Initialize();
    }

    public ToolStripDropDownButton(Image? image)
        : base(text: null, image, onClick: null)
    {
        Initialize();
    }

    public ToolStripDropDownButton(string? text, Image? image)
        : base(text, image, onClick: null)
    {
        Initialize();
    }

    public ToolStripDropDownButton(string? text, Image? image, EventHandler? onClick)
        : base(text, image, onClick)
    {
        Initialize();
    }

    public ToolStripDropDownButton(string? text, Image? image, EventHandler? onClick, string? name)
        : base(text, image, onClick, name)
    {
        Initialize();
    }

    public ToolStripDropDownButton(string? text, Image? image, params ToolStripItem[]? dropDownItems)
        : base(text, image, dropDownItems)
    {
        Initialize();
    }

    protected override AccessibleObject CreateAccessibilityInstance()
    {
        return new ToolStripDropDownButtonAccessibleObject(this);
    }

    [DefaultValue(true)]
    public new bool AutoToolTip
    {
        get => base.AutoToolTip;
        set => base.AutoToolTip = value;
    }

    protected override bool DefaultAutoToolTip
    {
        get
        {
            return true;
        }
    }

    [DefaultValue(true)]
    [SRDescription(nameof(SR.ToolStripDropDownButtonShowDropDownArrowDescr))]
    [SRCategory(nameof(SR.CatAppearance))]
    public bool ShowDropDownArrow
    {
        get
        {
            return _showDropDownArrow;
        }
        set
        {
            if (_showDropDownArrow != value)
            {
                _showDropDownArrow = value;
                InvalidateItemLayout(PropertyNames.ShowDropDownArrow);
            }
        }
    }

    /// <summary>
    ///  Creates an instance of the object that defines how image and text
    ///  gets laid out in the ToolStripItem
    /// </summary>
    private protected override ToolStripItemInternalLayout CreateInternalLayout()
    {
        return new ToolStripDropDownButtonInternalLayout(this);
    }

    protected override ToolStripDropDown CreateDefaultDropDown()
    {
        // AutoGenerate a ToolStrip DropDown - set the property so we hook events
        return new ToolStripDropDownMenu(this, isAutoGenerated: true);
    }

    /// <summary>
    ///  Called by all constructors of ToolStripButton.
    /// </summary>
    private void Initialize()
    {
        SupportsSpaceKey = true;
    }

    /// <summary>
    ///  Overriden to invoke displaying the popup.
    /// </summary>
    protected override void OnMouseDown(MouseEventArgs e)
    {
        if ((Control.ModifierKeys != Keys.Alt) &&
            (e.Button == MouseButtons.Left))
        {
            if (DropDown.Visible)
            {
                ToolStripManager.ModalMenuFilter.CloseActiveDropDown(DropDown, ToolStripDropDownCloseReason.AppClicked);
            }
            else
            {
                // opening should happen on mouse down.
                Debug.Assert(ParentInternal is not null, "Parent is null here, not going to get accurate ID");
                _openMouseId = (ParentInternal is null) ? (byte)0 : ParentInternal.GetMouseId();
                ShowDropDown(/*mousePush =*/true);
            }
        }

        base.OnMouseDown(e);
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        if ((Control.ModifierKeys != Keys.Alt) &&
            (e.Button == MouseButtons.Left))
        {
            Debug.Assert(ParentInternal is not null, "Parent is null here, not going to get accurate ID");
            byte closeMouseId = (ParentInternal is null) ? (byte)0 : ParentInternal.GetMouseId();
            if (closeMouseId != _openMouseId)
            {
                _openMouseId = 0;  // reset the mouse id, we should never get this value from toolstrip.
                ToolStripManager.ModalMenuFilter.CloseActiveDropDown(DropDown, ToolStripDropDownCloseReason.AppClicked);
                Select();
            }
        }

        base.OnMouseUp(e);
    }

    protected override void OnMouseLeave(EventArgs e)
    {
        _openMouseId = 0;  // reset the mouse id, we should never get this value from toolstrip.
        base.OnMouseLeave(e);
    }

    /// <summary>
    ///  Inheriting classes should override this method to handle this event.
    /// </summary>
    protected override void OnPaint(PaintEventArgs e)
    {
        if (Owner is not null)
        {
            ToolStripRenderer renderer = Renderer!;
            Graphics g = e.Graphics;

            renderer.DrawDropDownButtonBackground(new ToolStripItemRenderEventArgs(e.Graphics, this));

            if ((DisplayStyle & ToolStripItemDisplayStyle.Image) == ToolStripItemDisplayStyle.Image)
            {
                renderer.DrawItemImage(new ToolStripItemImageRenderEventArgs(g, this, InternalLayout.ImageRectangle));
            }

            if ((DisplayStyle & ToolStripItemDisplayStyle.Text) == ToolStripItemDisplayStyle.Text)
            {
                renderer.DrawItemText(new ToolStripItemTextRenderEventArgs(g, this, Text, InternalLayout.TextRectangle, ForeColor, Font, InternalLayout.TextFormat));
            }

            if (ShowDropDownArrow)
            {
                Rectangle dropDownArrowRect = (InternalLayout is ToolStripDropDownButtonInternalLayout layout) ? layout.DropDownArrowRect : Rectangle.Empty;

                Color arrowColor;
                if (Selected && !Pressed && SystemInformation.HighContrast)
                {
                    arrowColor = Enabled ? SystemColors.HighlightText : SystemColors.ControlDark;
                }
                else
                {
                    arrowColor = Enabled ? SystemColors.ControlText : SystemColors.ControlDark;
                }

                renderer.DrawArrow(new ToolStripArrowRenderEventArgs(g, this, dropDownArrowRect, arrowColor, ArrowDirection.Down));
            }
        }
    }

    protected internal override bool ProcessMnemonic(char charCode)
    {
        // checking IsMnemonic is not necessary - toolstrip does this for us.
        if (HasDropDownItems)
        {
            Select();
            ShowDropDown();
            return true;
        }

        return false;
    }
}
